﻿using UnityEngine;
using UnityView.Utils;

namespace UnityView
{
    // 表格视图适配器
    public interface IGridAdapter
    {
        int GetCount();
        IViewLayout GetConvertView(int index, IViewLayout view);
    }

    /// <summary>
    /// 
    /// </summary>
    public class GridView : AbsAdapterView<IGridAdapter>
    {
        public GridView(string name = "Grid View") : this(UICanvas.GetInstance(), name)
        {
        }
        
        public GridView(IViewLayout parent, string name = "Grid View") : base(parent, name)
        {
        }

        public int Row { get; protected set; }
        public int Column { get; protected set; }

        public override void OnAdapterAttached(IGridAdapter adapter)
        {
            ItemCount = Adapter.GetCount();
            UpdateVisibleItemCount();
            UpdateContentSize();
            Reload();
        }

        protected Vector2 GridItemSize = new Vector2(100, 100);

        public Vector2 ItemSize
        {
            get => GridItemSize;
            set
            {
                ScrollRect.StopMovement();
                GridItemSize = value;
                if (Adapter == null) return;
                UpdateContentSize();
                Reload();
            }
        }

        public override void ScrollToTop(int index = 0)
        {
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    index = index / Row;
                    ContentTransform.anchoredPosition = new Vector2(index * (Spacing.x + ItemSize.x), 0);
                    break;
                case Orientation.Vertical:
                    index = index / Column;
                    ContentTransform.anchoredPosition = new Vector2(0, index * (Spacing.y + ItemSize.y));
                    break;
            }
        }

        public override void UpdateVisibleItemCount()
        {
            VisibleItemCount = 0;
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    VisibleItemCount = (Mathf.CeilToInt((Width - Spacing.x) / (ItemSize.x + Spacing.x)) + 1) * Row;
                    break;
                case Orientation.Vertical:
                    VisibleItemCount = (Mathf.CeilToInt((Height - Spacing.y) / (ItemSize.y + Spacing.y)) + 1) * Column;
                    break;
            }

            if (StartIndex + VisibleItemCount > ItemCount) VisibleItemCount = ItemCount - StartIndex;
        }

        protected float AnchorOffset = 0;

        public override Vector2 GetItemPosition(int index)
        {
            int offsetIndex = 0;
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    offsetIndex = index % Row;
                    return new Vector2(offsetIndex * (ItemSize.x + Spacing.x) + Spacing.x,
                        -AnchorOffset - ((index / Row) * (ItemSize.y + Spacing.y)) - Spacing.y);
                case Orientation.Vertical:
                    offsetIndex = index % Column;
                    return new Vector2(AnchorOffset + offsetIndex * (ItemSize.x + Spacing.x) + Spacing.x,
                        -((index / Column) * (ItemSize.y + Spacing.y)) - Spacing.y);
            }

            return Vector2.zero;
        }

        public override int GetItemIndex(Vector2 vector2)
        {
            float ox = vector2.x - Spacing.x;
            float oy = vector2.y - Spacing.y;
            float dx;
            float dy;
            int cx;
            int cy;
            float ux = ItemSize.x + Spacing.x;
            float uy = ItemSize.y + Spacing.y;
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    ox += ContentTransform.anchoredPosition.y;
                    oy -= AnchorOffset;
                    dx = ox.Modf(ItemSize.x + Spacing.x);
                    if (dx > ItemSize.x) return -1;
                    dy = oy.Modf(ItemSize.y + Spacing.y);
                    if (dy > ItemSize.y) return -1;
                    cy = Mathf.FloorToInt(oy / ItemSize.y);
                    if (cy >= Row) return -1;
                    cx = Mathf.FloorToInt(ox / ItemSize.x);
                    return cx * Row + cy;
                default:
                    ox -= AnchorOffset;
                    oy += ContentTransform.anchoredPosition.y;
                    dx = ox.Modf(ux);
                    if (dx > ItemSize.x) return -1;
                    dy = oy.Modf(uy);
                    if (dy > ItemSize.y) return -1;
                    cx = Mathf.FloorToInt(ox / ux);
                    if (cx >= Column) return -1;
                    cy = Mathf.FloorToInt(oy / uy);
                    return cy * Column + cx;
            }
        }

        protected override int GetStartIndex()
        {
            float anchor;
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    anchor = -ContentTransform.anchoredPosition.x;
                    StartIndex = (int) (anchor / (ItemSize.x + Spacing.x));
                    if (StartIndex < 0) StartIndex = 0;
                    if (StartIndex > Column - 1) StartIndex = Column - 1;
                    StartIndex *= Row;
                    break;
                case Orientation.Vertical:
                    anchor = ContentTransform.anchoredPosition.y;
                    StartIndex = (int) (anchor / (ItemSize.y + Spacing.y));
                    if (StartIndex < 0) StartIndex = 0;
                    if (StartIndex > Row - 1) StartIndex = Row - 1;
                    StartIndex *= Column;
                    break;
            }

            UpdateVisibleItemCount();
            return StartIndex;
        }

        // protected LinkedList<AdapterCellHolder> Items = new LinkedList<AdapterCellHolder>();
        // protected AdapterCellCache<AdapterCellHolder> Cache = new AdapterCellCache<AdapterCellHolder>();

        public override void Reload()
        {
            // 停止滚动
            ScrollRect.StopMovement();
            if (Adapter == null) return;

            ItemCount = Adapter.GetCount();
            UpdateContentSize();

            StartIndex = GetStartIndex();
            // UpdateVisibleItemCount();

            CellCache.Reset();
            LayoutSubviews();
            CellCache.Clear();

            // for (int i = 0; i < VisibleItemCount; i++)
            // {
            //     LinkedListNode<AdapterCellHolder> node = Items.First;
            //     cells.Add(node == null ? new AdapterCellHolder() : node.Value);
            //     if (Items.Count > 0) Items.RemoveFirst();
            // }
            //
            // foreach (var item in Items)
            // {
            //     Cache.Enqueue(item);
            // }
            //
            // Items.Clear();
            //
            // for (int i = 0; i < VisibleItemCount; i++)
            // {
            //     var cell = cells[i];
            //     int index = StartIndex + i;
            //     IViewLayout viewLayout = Adapter.GetConvertView(index, cell.View);
            //     viewLayout.ParentView = ContentView;
            //     cell.Update(viewLayout, index, GetItemPosition(index), ItemSize);
            //     Items.AddLast(cell);
            // }
        }

        public override void LayoutSubviews()
        {
            var info = CellCache.Inquire(StartIndex, VisibleItemCount);
            int dirtyCount = info.DirtyCount;
            if (dirtyCount == 0) return;
            var node = info.Node;
            int dirtyIndex = info.DirtyIndex;
            // Debug.Log($"VisibleItemCount: {VisibleItemCount}, dirtyIndex: {dirtyIndex}, dirtyCount: {dirtyCount}");
            for (int i = 0; i < dirtyCount; i++)
            {
                AdapterCellHolder holder = node.Value;
                int index = dirtyIndex + i;
                IViewLayout view = Adapter.GetConvertView(index, holder.View);
                view.ParentView = ContentView;
                holder.Update(view, index, GetItemPosition(index), ItemSize);
                node = node.Next;
            }

            // if (delta > 0)
            // {
            //     // 此时视图向上运动，StartIndex 增大 
            //     LinkedListNode<AdapterCellHolder> node = Items.First;
            //     int count = 0;
            //     while (node != null)
            //     {
            //         if (node.Value.Index >= StartIndex) break;
            //         count++;
            //         node = node.Next;
            //     }
            //
            //     for (int i = 0; i < count; i++)
            //     {
            //         Cache.Enqueue(Items.First.Value);
            //         Items.RemoveFirst();
            //     }
            //
            //     count = Items.Count;
            //     int missing = VisibleItemCount - count;
            //     for (int i = 0; i < missing; i++)
            //     {
            //         //int index = StartIndex + i - 1;
            //         int index = Items.Count == 0 ? 0 : Items.Last.Value.Index + 1;
            //
            //         AdapterCellHolder cellHolder = Cache.Dequeue();
            //         IViewLayout viewLayout = Adapter.GetConvertView(index, cellHolder.View);
            //         viewLayout.ParentView = ContentView;
            //         cellHolder.Update(viewLayout, index, GetItemPosition(index), ItemSize);
            //         Items.AddLast(cellHolder);
            //     }
            // }
            // else
            // {
            //     // 此时视图向下运动
            //     LinkedListNode<AdapterCellHolder> node = Items.Last;
            //     int count = 0;
            //     while (node != null)
            //     {
            //         if (node.Value.Index < StartIndex + VisibleItemCount) break;
            //         count++;
            //         node = node.Previous;
            //     }
            //
            //     for (int i = 0; i < count; i++)
            //     {
            //         Cache.Enqueue(Items.Last.Value);
            //         Items.RemoveLast();
            //     }
            //
            //     count = Items.Count;
            //     int missing = VisibleItemCount - count;
            //     for (int i = 0; i < missing; i++)
            //     {
            //         int index = Items.Count == 0 ? 0 : Items.First.Value.Index - 1;
            //         if (index < 0) index = 0;
            //
            //         AdapterCellHolder cellHolder = Cache.Dequeue();
            //         IViewLayout viewLayout = Adapter.GetConvertView(index, cellHolder.View);
            //         viewLayout.ParentView = ContentView;
            //         cellHolder.Update(viewLayout, index, GetItemPosition(index), ItemSize);
            //         Items.AddFirst(cellHolder);
            //     }
            // }
            //
            // LastRepositionPosition = ContentTransform.anchoredPosition;
        }

        protected override Vector2 UpdateContentSize()
        {
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    // 水平滚动时，先确定行，再确定列
                    Row = (int) ((Height - Spacing.y) / (ItemSize.y + Spacing.y));
                    Column = (ItemCount + Row - 1) / Row;
                    ContentTransform.sizeDelta = new Vector2(Column * (ItemSize.x + Spacing.x) + Spacing.x, Height);
                    break;
                case Orientation.Vertical:
                    // 竖直滚动时，先确定列，再确定行
                    float unit = ItemSize.x + Spacing.x;
                    Column = Mathf.FloorToInt((Width - Spacing.x) / unit);
                    AnchorOffset = (Width - (Column * unit + Spacing.x)) / 2;
                    Row = (ItemCount + Column - 1) / Column;
                    ContentTransform.sizeDelta = new Vector2(Width, Row * (ItemSize.y + Spacing.y) + Spacing.y);
                    break;
            }

            UpdateVisibleItemCount();
            return ContentSize;
        }
    }
}